use egui::{Pos2, Vec2};

pub trait NodeViewer<T> {
    fn draw(&mut self, node:&mut Node<T>, ui:&mut egui::Ui)->egui::Rect {
        let header_frame = egui::Frame::window(&ui.style());
        header_frame.show(ui, |ui|{
            self.draw_header(node, ui);
            node.header_rect = Some(ui.min_rect());
        });
        ui.min_rect()
    }

    fn draw_header(&mut self, node:&mut Node<T>, ui:&mut egui::Ui);

    // fn inputs(&self) -> usize;
    // fn outputs(&self) -> usize;
    // fn draw_input(&self, index:usize, node:&mut Node<T>, ui:&mut egui::Ui);
    // fn draw_output(&self, index:usize, node:&mut Node<T>, ui:&mut egui::Ui);
}

#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(bound(serialize = "T: serde::Serialize", deserialize = "T: serde::Deserialize<'de>")))]
pub struct Node<T> {
    pub(crate) data:T,
    pub(crate) position:Pos2,
    pub(crate) size:Vec2,
    pub(crate) header_rect:Option<egui::Rect>,
    pub(crate) body_rect:Option<egui::Rect>,
}

impl <T> Node<T> {
    pub fn new(data:T) -> Self {
        Node {
            data,
            position: Pos2::ZERO,
            size: Vec2::ZERO,
            header_rect: None,
            body_rect: None,
        }
    }

    pub fn with_position(data:T, position:Pos2) -> Self {
        Node {
            data,
            position,
            size: Vec2::ZERO,
            header_rect: None,
            body_rect: None,
        }
    }

    pub fn with_size(data:T, size:Vec2) -> Self {
        Node {
            data,
            position: Pos2::ZERO,
            size,
            header_rect: None,
            body_rect: None,
        }
    }

    pub fn position(&self) -> Pos2 {
        self.position
    }

    pub fn set_position(&mut self, position:Pos2) {
        self.position = position;
    }

    pub fn data(&self) -> &T {
        &self.data
    }

    pub fn data_mut(&mut self) -> &mut T {
        &mut self.data
    }
}


